前面花了3篇的篇輻來講VectorDrawable 及 VectorDrawable animation。
我們就來做一個從Play變Pause的動畫,用慢動作來看如下圖:

1.為了讓從暫停到撥放有旋轉90度的效果,所以我們將撥放的Icon做成朝上的三角形
2.為了讓2個Icon可以變成動畫,我們知道pathData要是成對的,所以我們把三角形分為2半來處理,三角形的左右兩半會對映到Pause的左右兩塊
PathData
Play:M12,16 H5 L8.5,10.5 L12,5 M12,16 H19 L15.5,10.5 L12,5
pause:M10,18 H6 L6,6 L10,6 M14,18 H18 L18,6 L14,6

先來看一下我們在drawable放了哪些檔案
icon_Play.xml
因為我們在pathData裡畫的是朝上的三角形,這裡加上rotation=90,讓三角形變成play的樣子。
<vector xmlns:android="http://schemas.android.com/apk/res/android"
    android:width="120dp"
    android:height="120dp"
    android:viewportHeight="24"
    android:viewportWidth="24">
    <group
        android:name="iconGroup"
        android:pivotX="12"
        android:pivotY="12"
        android:rotation="90">
        <path
            android:name="iconPath"
            android:fillColor="#FF000000"
            android:pathData="@string/play_path" />
    </group>
</vector>
icon_pause.xml
<vector xmlns:android="http://schemas.android.com/apk/res/android"
    android:width="120dp"
    android:height="120dp"
    android:viewportWidth="24.0"
    android:viewportHeight="24.0">
    <group
        android:name="iconGroup"
        android:pivotX="12"
        android:pivotY="12"
        >
    <path
        android:name="iconPath"
        android:fillColor="#FF000000"
        android:pathData="@string/pause_path" />
    </group>
</vector>
從play到pause的動畫
第1個objectAnimator:旋轉從90度轉到180度
為什麼從90度開始呢,因為一開始我們就將icon_paly旋轉90為play的三角形了。從90旋轉至180會讓play從朝上的三角形變成朝右的,會讓pause轉180度還是一樣。
第二個objectAnimator
pathData的轉換,由play轉為pause
adv_play_to_pause.xml
<animated-vector xmlns:android="http://schemas.android.com/apk/res/android"
    xmlns:aapt="http://schemas.android.com/aapt"
    xmlns:tools="http://schemas.android.com/tools"
    android:drawable="@drawable/ic_pause"
    tools:targetApi="lollipop">
    <target android:name="iconGroup">
        <aapt:attr name="android:animation">
            <set>
                <objectAnimator
                    android:duration="4000"
                    android:interpolator="@android:interpolator/fast_out_slow_in"
                    android:propertyName="rotation"
                    android:valueFrom="90"
                    android:valueTo="180" />
            </set>
        </aapt:attr>
    </target>
    <target android:name="iconPath">
        <aapt:attr name="android:animation">
            <objectAnimator
                android:duration="4000"
                android:interpolator="@android:interpolator/fast_out_slow_in"
                android:propertyName="pathData"
                android:valueFrom="@string/play_path"
                android:valueTo="@string/pause_path"
                android:valueType="pathType" />
        </aapt:attr>
    </target>
</animated-vector>
從pause到play的動畫
第1個objectAnimator
旋轉從0轉到90度
第二個objectAnimator
pathData的轉換,由pause轉為play
<animated-vector xmlns:android="http://schemas.android.com/apk/res/android"
    xmlns:aapt="http://schemas.android.com/aapt"
    android:drawable="@drawable/ic_play"
    >
    <target android:name="iconGroup">
        <aapt:attr name="android:animation">
            <set>
                <objectAnimator
                    android:duration="4000"
                    android:interpolator="@android:interpolator/fast_out_slow_in"
                    android:propertyName="rotation"
                    android:valueFrom="0"
                    android:valueTo="90" />
            </set>
        </aapt:attr>
    </target>
    <target android:name="iconPath">
        <aapt:attr name="android:animation">
            <objectAnimator
                android:duration="4000"
                android:interpolator="@android:interpolator/fast_out_slow_in"
                android:propertyName="pathData"
                android:valueFrom="@string/pause_path"
                android:valueTo="@string/play_path"
                android:valueType="pathType" />
        </aapt:attr>
    </target>
</animated-vector>
這邊可以發現,我們play的pathData與pause的pathData放在strings.xml,因為在icon、animation都會用到。
<resources>
    <string name="pause_path">M10,18 H6 L6,6 L10,6 M14,18 H18 L18,6 L14,6</string>
    <string name="play_path">M12,16 H5 L8.5,10.5 L12,5 M12,16 H19 L15.5,10.5 L12,5</string>
</resources>
最後,animated-selector裡就是play與pause的icon與transition了。
as_playpause.xml
<animated-selector xmlns:android="http://schemas.android.com/apk/res/android"
    xmlns:app="http://schemas.android.com/apk/res-auto"
    >
    <item
        android:id="@+id/pause"
        android:drawable="@drawable/ic_pause"
        app:state_pause="true" />
    <item
        android:id="@+id/play"
        android:drawable="@drawable/ic_play" />
    <transition
        android:drawable="@drawable/avd_pause_to_play"
        android:fromId="@id/pause"
        android:reversible="false"
        android:toId="@id/play" />
    <transition
        android:drawable="@drawable/avd_play_to_pause"
        android:fromId="@id/play"
        android:reversible="false"
        android:toId="@id/pause" />
</animated-selector>
activity_main.xml,加上ImageView
<LinearLayout xmlns:android="http://schemas.android.com/apk/res/android"
    xmlns:app="http://schemas.android.com/apk/res-auto"
    xmlns:tools="http://schemas.android.com/tools"
    android:layout_width="match_parent"
    android:layout_height="match_parent"
    android:orientation="vertical"
    android:gravity="center"
    tools:context=".MainActivity">
    <ImageView
        android:id="@+id/play"
        android:layout_width="wrap_content"
        android:layout_height="wrap_content"
        app:srcCompat="@drawable/as_playpause" />
</LinearLayout>
在MainActivity切換state
class MainActivity : AppCompatActivity() {
    private val STATE_PLAY = intArrayOf(R.attr.state_play, -R.attr.state_pause)
    private val STATE_PAUSE = intArrayOf(-R.attr.state_play, R.attr.state_pause)
    var isPlay = true
    override fun onCreate(savedInstanceState: Bundle?) {
        super.onCreate(savedInstanceState)
        setContentView(R.layout.activity_main)
        play.setImageState(STATE_PLAY, true)
        play.setOnClickListener {
            if (isPlay) {
                play.setImageState(STATE_PAUSE, true)
            } else {
                play.setImageState(STATE_PLAY, true)
            }
            isPlay = !isPlay
        }
    }
}
完整程式:
https://github.com/evanchen76/PlayPauseAnimation
線上課程:
Android 動畫入門到進階
Android UI 進階實戰(Material Design Component)
出版書:
Android TDD 測試驅動開發:從 UnitTest、TDD 到 DevOps 實踐